/* 
 * File:   VistaNivel.cpp
 * Author: agu
 * 
 * Created on 7 de junio de 2014, 1:12
 */

#include "editor_VistaNivel.h"
#include <iostream>

VistaNivel::VistaNivel() {
    this->builder = Gtk::Builder::create();
    try {
        this->builder->add_from_file("gladeInterfaces/nivelTamanioFijo.glade");
    } catch (const Glib::FileError& ex) {
        std::cout << "FileError: " << ex.what() << std::endl;

    } catch (const Glib::MarkupError& ex) {
        std::cout << "MarkupError: " << ex.what() << std::endl;

    } catch (const Gtk::BuilderError& ex) {
        std::cout << "BuilderError: " << ex.what() << std::endl;

    }
    this->buttonPressed = "";
    this->gridOk = false;

    this->loadWidgets();
    this->createModel();
    this->connectWidgets();
}

void VistaNivel::loadWidgets() {
    this->builder->get_widget("window", this->window);
    this->builder->get_widget("entryName", this->entryName);
    this->builder->get_widget("buttonSave", this->buttonSave);
    this->builder->get_widget("buttonBack", this->buttonBack);
    this->builder->get_widget("buttonOk", this->buttonOk);
    this->builder->get_widget("buttonOk2", this->buttonOk2);
    this->builder->get_widget("buttonGenerate", this->buttonGenerate);
    this->builder->get_widget("buttonReset", this->buttonReset);
    this->builder->get_widget("buttonZombieRed", this->buttonZombieRed);
    this->builder->get_widget("buttonZombieBlue", this->buttonZombieBlue);
    this->builder->get_widget("buttonZombieGreen", this->buttonZombieGreen);
    this->builder->get_widget("buttonFriend", this->buttonFriend);
    this->builder->get_widget("buttonGround", this->buttonGround);
    this->builder->get_widget("buttonBox", this->buttonBox);
    this->builder->get_widget("buttonMetal", this->buttonMetal);
    this->builder->get_widget("buttonBoxEnemy", this->buttonBoxEnemy);
    this->builder->get_widget("buttonPlayer", this->buttonPlayer);
    this->builder->get_widget("grid", this->grid);
    this->builder->get_widget("comboSize", this->comboSizeMap);
    this->builder->get_widget("message", this->message);
    this->builder->get_widget("messageError", this->messageError);
    listTargets.push_back(Gtk::TargetEntry("STRING"));
    listTargets.push_back(Gtk::TargetEntry("text/plain"));


}

void VistaNivel::connectWidgets() {
    this->window->signal_hide().connect(sigc::mem_fun(this, &VistaNivel::close));
    this->buttonBack->signal_clicked().connect(sigc::mem_fun(this, &VistaNivel::back));
    this->buttonSave->signal_clicked().connect(sigc::mem_fun(this, &VistaNivel::save));
    this->buttonOk->signal_clicked().connect(sigc::mem_fun(this, &VistaNivel::hideMessageError));
    this->buttonOk2->signal_clicked().connect(sigc::mem_fun(this, &VistaNivel::saveExit));
    this->buttonGenerate->signal_clicked().connect(sigc::mem_fun(this, &VistaNivel::generateGridMap));
    this->buttonReset->signal_clicked().connect(sigc::mem_fun(this, &VistaNivel::reset));
    this->comboSizeMap->signal_changed().connect(sigc::mem_fun(this, &VistaNivel::onComboSizeMapChanged));

    buttonGround->signal_pressed().connect(sigc::mem_fun(this, &VistaNivel::buttonGroundPressed));
    buttonGround->drag_source_set(listTargets);
    buttonGround->signal_drag_data_get().connect(sigc::mem_fun(*this,
            &VistaNivel::on_button_drag_data_get));

    buttonMetal->signal_pressed().connect(sigc::mem_fun(this, &VistaNivel::buttonMetalPressed));
    buttonMetal->drag_source_set(listTargets);
    buttonMetal->signal_drag_data_get().connect(sigc::mem_fun(*this,
            &VistaNivel::on_button_drag_data_get));

    buttonBox->signal_pressed().connect(sigc::mem_fun(this, &VistaNivel::buttonBoxPressed));
    buttonBox->drag_source_set(listTargets);
    buttonBox->signal_drag_data_get().connect(sigc::mem_fun(*this,
            &VistaNivel::on_button_drag_data_get));

    buttonBoxEnemy->signal_pressed().connect(sigc::mem_fun(this, &VistaNivel::buttonBoxEnemyPressed));
    buttonBoxEnemy->drag_source_set(listTargets);
    buttonBoxEnemy->signal_drag_data_get().connect(sigc::mem_fun(*this,
            &VistaNivel::on_button_drag_data_get));

    buttonZombieBlue->signal_pressed().connect(sigc::mem_fun(this, &VistaNivel::buttonZombieBluePressed));
    buttonZombieBlue->drag_source_set(listTargets);
    buttonZombieBlue->signal_drag_data_get().connect(sigc::mem_fun(*this,
            &VistaNivel::on_button_drag_data_get));

    buttonZombieRed->signal_pressed().connect(sigc::mem_fun(this, &VistaNivel::buttonZombieRedPressed));
    buttonZombieRed->drag_source_set(listTargets);
    buttonZombieRed->signal_drag_data_get().connect(sigc::mem_fun(*this,
            &VistaNivel::on_button_drag_data_get));

    buttonZombieGreen->signal_pressed().connect(sigc::mem_fun(this, &VistaNivel::buttonZombieGreenPressed));
    buttonZombieGreen->drag_source_set(listTargets);
    buttonZombieGreen->signal_drag_data_get().connect(sigc::mem_fun(*this,
            &VistaNivel::on_button_drag_data_get));

    buttonFriend->signal_pressed().connect(sigc::mem_fun(this, &VistaNivel::buttonFriendPressed));
    buttonFriend->drag_source_set(listTargets);
    buttonFriend->signal_drag_data_get().connect(sigc::mem_fun(*this,
            &VistaNivel::on_button_drag_data_get));

    buttonPlayer->signal_pressed().connect(sigc::mem_fun(this, &VistaNivel::buttonPlayerPressed));
    buttonPlayer->drag_source_set(listTargets);
    buttonPlayer->signal_drag_data_get().connect(sigc::mem_fun(*this,
            &VistaNivel::on_button_drag_data_get));
}

VistaNivel::~VistaNivel() {
    //Limpiar Memorias
    delete this->window;
}

void VistaNivel::run() {
    this->window->show();
}

void VistaNivel::runLoadedLevel() {
    Glib::ustring name = this->level->getName().c_str();
    this->entryName->set_text(name);
    this->grid->check_resize();
    this->grid->drag_dest_set(listTargets);
    this->grid->signal_drag_data_received().connect(sigc::mem_fun(*this,
            &VistaNivel::on_label_drop_drag_data_received));
    this->level->loadGridMap(this->grid);
     this->gridOk = true;
    this->window->show_all();
}

void VistaNivel::close() {
    //Limpiar Memoria
    this->reset();
    this->level = NULL;
    this->window->close();
}

void VistaNivel::back() {
    //Limpiar Memoria
    this->reset();
    this->window->set_visible(false);
    this->windowsBack->set_visible(true);
}

void VistaNivel::save() {
    //Limpiar Memoria
    string inputText(this->entryName->get_chars(0, -1));
    this->level->setName(inputText);
    this->level->setMap(this->grid);
    if (inputText.empty()) {
        this->messageError->set_secondary_text("Debe completar un nombre para el nivel", false);
        this->messageError->show();
        this->level->reset();
        return;
    }
    if (!this->gridOk) {
        std::cout << "Grilla sin completar" << std::endl;
        this->messageError->set_secondary_text("Debe generar el mapa", false);
        this->messageError->show();
        this->level->reset();
        return;
    }
    string msjError;
    if (!this->level->validate(msjError)) {
        std::cout << "No cumple con las condiciones para la dificultad dada" << std::endl;
        this->messageError->set_secondary_text(msjError.c_str(), false);
        this->messageError->show();
        this->level->reset();
        return;
    }
    this->message->show();

}

void VistaNivel::setWindowsBack(Gtk::Window *windowBack) {
    this->windowsBack = windowBack;
}

void VistaNivel::setLevel(Nivel* level) {
    this->level = level;
}

unsigned int VistaNivel::getId() {
    return this->level->getId();
}

void VistaNivel::hideMessageError() {
    this->messageError->hide();
}

void VistaNivel::saveExit() {
    this->level->save();
    this->message->hide();
    this->window->set_visible(false);
    this->windowsBack->set_visible(true);
}

void VistaNivel::generateGridMap() {
    this->window->set_events(Gdk::BUTTON_PRESS_MASK);

    this->grid->check_resize();
    this->grid->drag_dest_set(listTargets);
    this->grid->signal_drag_data_received().connect(sigc::mem_fun(*this,
            &VistaNivel::on_label_drop_drag_data_received));
    if (this->level->checkDimension()) {
        this->buttonGenerate->set_sensitive(false);
        this->comboSizeMap->set_sensitive(false);
        //Por cada fila
        for (unsigned int i = 0; i < this->level->getMapHeight(); i++) {
            //Recorro todas las columnas
            for (unsigned int j = 0; j < this->level->getMapWidth(); j++) {
                Gtk::Image* img = Gtk::manage(new Gtk::Image);
                img->set("gladeInterfaces/floor.png"); //Emprolijar                
                this->grid->attach(*img, i, j, 1, 1);
            }
        }
        this->gridOk = true;
        this->window->show_all();
    } else {
        //Lanzar mensaje de que el tamaño no es el adecuado
    }
}

void VistaNivel::on_button_drag_data_get(
        const Glib::RefPtr<Gdk::DragContext>& context,
        Gtk::SelectionData& selection_data, guint info, guint time) {
    selection_data.set(selection_data.get_target(), 8 /* 8 bits format */,
            (const guchar*) this->buttonPressed.c_str(),
            this->buttonPressed.size());

}

void VistaNivel::on_label_drop_drag_data_received(
        const Glib::RefPtr<Gdk::DragContext>& context, int x, int y,
        const Gtk::SelectionData& selection_data, guint info, guint time) {

    const int length = selection_data.get_length();
    if ((length >= 0) && (selection_data.get_format() == 8)) {
        this->intersect(x, y);
    }
    context->drag_finish(false, false, time);
}

void VistaNivel::buttonGroundPressed() {
    this->buttonPressed = "floor";
}

void VistaNivel::buttonMetalPressed() {
    this->buttonPressed = "metal";
}

void VistaNivel::buttonBoxPressed() {
    this->buttonPressed = "box";
}

void VistaNivel::buttonBoxEnemyPressed() {
    this->buttonPressed = "boxEnemy";
}

void VistaNivel::buttonZombieRedPressed() {
    this->buttonPressed = "zombieRed";
}

void VistaNivel::buttonZombieGreenPressed() {
    this->buttonPressed = "zombieGreen";
}

void VistaNivel::buttonZombieBluePressed() {
    this->buttonPressed = "zombieBlue";
}

void VistaNivel::buttonFriendPressed() {
    this->buttonPressed = "friend";
}

void VistaNivel::buttonPlayerPressed() {
    this->buttonPressed = "player";
}

void VistaNivel::transformateCoordenades(int x, int y, int& newX, int& newY) {
    newX = x / 32;
    newY = y / 32;
}

void VistaNivel::intersect(int x, int y) {
    int posX = 0, posY = 0;
    this->transformateCoordenades(x, y, posX, posY);
    Gtk::Image* img = (Gtk::Image*) this->grid->get_child_at(posX, posY);
    if (img != NULL) {
        string pathImg = "gladeInterfaces/" + this->buttonPressed + ".png";
        img->set(pathImg);
    }
}

bool VistaNivel::cleanCell(GdkEventButton* event) {
    if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
        std::cout << "The drawing area was clicked"
                << std::endl;
    }
    return true;
}

void VistaNivel::reset() {
    //Por cada fila
    for (unsigned int i = 0; i < this->level->getMapHeight(); i++) {
        //Recorro todas las columnas
        for (unsigned int j = 0; j < this->level->getMapWidth(); j++) {
            this->grid->remove_column(j);
        }
        this->grid->remove_row(i);
    }
    this->level->reset();
    this->gridOk = false;
    this->level->setMapHeight(0);
    this->level->setMapWidth(0);
    this->buttonGenerate->set_sensitive(true);
    this->comboSizeMap->set_sensitive(true);
    this->entryName->delete_text(0, -1);
}

void VistaNivel::highlightGrid(
        const Glib::RefPtr<Gdk::DragContext>& context, int x, int y,
        const Gtk::SelectionData& selection_data, guint info, guint time) {

}

void VistaNivel::createModel() {
    //Create the Tree model:
    refTreeModelSizeMap = Gtk::ListStore::create(columnsSizeMap);
    comboSizeMap->set_model(refTreeModelSizeMap);

    //Fill the ComboBox's Tree Model:
    Gtk::TreeModel::Row row = *(refTreeModelSizeMap->append());
    row[columnsSizeMap.colSizeName] = "Chico";
    row = *(refTreeModelSizeMap->append());
    row[columnsSizeMap.colSizeName] = "Mediano";
    row = *(refTreeModelSizeMap->append());
    row[columnsSizeMap.colSizeName] = "Grande";
    comboSizeMap->set_active(row);
    comboSizeMap->pack_start(columnsSizeMap.colSizeName);
}

void VistaNivel::onComboSizeMapChanged() {
    Gtk::TreeModel::iterator iter = comboSizeMap->get_active();
    if (iter) {
        Gtk::TreeModel::Row row = *iter;
        if (row) {
            //Get the data for the selected row, using our knowledge of the tree
            //model:
            Glib::ustring name = row[columnsSizeMap.colSizeName];
            this->level->setSizeMap(name);
        }
    } else
        std::cout << "invalid iter" << std::endl;

}